package com.xuecheng.checkcode.service;

import cn.hutool.core.util.StrUtil;
import com.xuecheng.checkcode.model.CheckCodeResultDTO;
import com.xuecheng.checkcode.model.GenerateCheckCodeParamsDTO;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * @author Mr.M
 * @version 1.0
 * @description 验证码接口
 * @date 2022/9/29 15:59
 */
@Slf4j
public abstract class AbstractCheckCodeService implements CheckCodeService {

    /**
     * 验证码生成器
     */
    protected CheckCodeGenerator checkCodeGenerator;

    /**
     * 验证码key存储
     */
    protected KeyGenerator keyGenerator;

    /**
     * 验证码存储
     */
    protected CheckCodeStore checkCodeStore;

    /**
     * 设置验证码生成器
     * @param checkCodeGenerator 生成器
     */
    public abstract void setCheckCodeGenerator(CheckCodeGenerator checkCodeGenerator);

    /**
     * 设置验证码key生成器
     * @param keyGenerator key生成器
     */
    public abstract void setKeyGenerator(KeyGenerator keyGenerator);

    /**
     * 设置验证码存储
     * @param checkCodeStore 验证码存储器
     */
    public abstract void setCheckCodeStore(CheckCodeStore checkCodeStore);

    /**
     * 生成验证码模板
     * @param code_length 验证码长度
     * @param keyPrefix key前缀
     * @param expire 过期时间
     * @return 生成结果
     */
    protected GenerateResult generate(Integer code_length, String keyPrefix, Integer expire) {
        // 生成指定位数的验证码
        String code = checkCodeGenerator.generate(code_length);
        log.debug("生成验证码:{}", code);
        // 生成一个key
        String key = keyGenerator.generate(keyPrefix);
        // 存储验证码
        checkCodeStore.set(key, code, expire);
        // 返回验证码生成结果
        return new GenerateResult(key, code);
    }

    @Data
    protected static class GenerateResult {

        /**
         * key
         */
        String key;

        /**
         * 验证码
         */
        String code;

        protected GenerateResult() {
        }

        protected GenerateResult(String key, String code) {
            this.key = key;
            this.code = code;
        }
    }

    /**
     * 生成验证码
     * @param generateCheckCodeParamsDTO 验证码参数
     * @return 生成结果
     */
    public abstract CheckCodeResultDTO generate(GenerateCheckCodeParamsDTO generateCheckCodeParamsDTO);

    /**
     * 校验验证码模板
     * @param key key
     * @param code 验证码
     * @return 校验结果
     */
    public boolean verify(String key, String code) {
        if (StrUtil.isBlank(key) || StrUtil.isBlank(code)) return false;
        String actual = checkCodeStore.get(key);
        if (actual == null) return false;
        boolean result = actual.equalsIgnoreCase(code);
        if (result) checkCodeStore.remove(key);
        return result;
    }
}
